﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Plugins
{
    public class PluginLoader
    {
        static string screenName = null;
        public static string ScreenName
        {
            get
            {
                if (screenName == null)
                {
                    screenName = System.Configuration.ConfigurationSettings.AppSettings["ScreenName"];
                    if (screenName == null || screenName.Trim() == "") screenName = "Anika";
                }
                return screenName;
            }
        }
        static PluginLoader()
        {
            System.Diagnostics.Trace.WriteLine("Plugin Loader Initializing");
            LoadPlugins();
            WatchForPlugins();
        }
        static System.Threading.Timer reloadPluginTimer;
        private static void WatchForPlugins()
        {
            System.IO.FileSystemWatcher fsw = new System.IO.FileSystemWatcher(PluginFolder, "*.dll");

            fsw.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.Security | NotifyFilters.Size;

            fsw.Changed += new FileSystemEventHandler(fsw_Changed);
            fsw.Created += new FileSystemEventHandler(fsw_Changed);
            fsw.Deleted += new FileSystemEventHandler(fsw_Changed);
            fsw.Renamed += new RenamedEventHandler(fsw_Changed);

            fsw.EnableRaisingEvents = true;
            System.Diagnostics.Trace.WriteLine("Watching for Plugin Changes");
            reloadPluginTimer = new System.Threading.Timer(new System.Threading.TimerCallback(ReloadPlugins), null, System.Threading.Timeout.Infinite, reloadSignal);
        }

        static int reloadSignal = 1000;
        static void ReloadPlugins(object state)
        {
            if (needsUpdate)
            {
                reloadPluginTimer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);            
                PluginList = new List<IPlugin>();
                LoadPlugins();
                needsUpdate = false;
                reloadPluginTimer.Change(System.Threading.Timeout.Infinite, reloadSignal);            
            }
        }
        static bool needsUpdate = false;
        static void fsw_Changed(object sender, System.IO.FileSystemEventArgs e)
        {
            needsUpdate = true;
        }
        public static List<IPlugin> PluginList = new List<IPlugin>();
        private static IPlugin DefaultPlugin = null;
        public static string Chat(string UserID, string Command, string Input)
        {
            try
            {
                if (PluginList == null || PluginList.Count == 0) LoadPlugins();
                foreach (IPlugin p in PluginList)
                {
                    foreach (string cmd in p.Command)
                    {
                        if (p.Messenger == null) p.Messenger = Messenger;
                        if (p.RootStore == null) p.RootStore = RootStore;
                        if (cmd == Command)
                        {
                            return p.Chat(cmd, UserID, Input);
                        }
                    }
                }
                if (DefaultPlugin != null) return DefaultPlugin.Chat("", UserID, string.Format("{0} {1}", Command, Input));
            }
            catch (Exception exc)
            {
                System.Diagnostics.Trace.WriteLine(exc.ToString());
            }
            return null;
        }
        static string pluginFolder = null;
        public static string PluginFolder
        {
            get
            {
                if (pluginFolder == null)
                    pluginFolder = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);

                if (!System.IO.Directory.Exists(pluginFolder)) System.IO.Directory.CreateDirectory(pluginFolder);
                return pluginFolder;
            }
        }
        static string pluginLoaderFolder = null;
        public static string PluginLoaderFolder
        {
            get
            {
                if (pluginLoaderFolder == null)
                    pluginLoaderFolder = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "_loader");

                if (!System.IO.Directory.Exists(pluginLoaderFolder)) System.IO.Directory.CreateDirectory(pluginLoaderFolder);
                return pluginLoaderFolder;
            }
        }
        public static MSNPSharp.Messenger Messenger { get; set; }
        public static string RootStore { get; set; }
        public static void LoadPlugins()
        {
            lock (PluginList)
            {
                System.Diagnostics.Trace.WriteLine("Scanning for plugins");
                PluginList = new List<IPlugin>();

                foreach (string dll in System.IO.Directory.GetFiles(PluginFolder, "*.dll"))
                {
                    string fullPath = System.IO.Path.Combine(PluginFolder, dll);
                    if (System.IO.File.Exists(fullPath))
                    {
                        try
                        {
                            //string loaderPath = fullPath;
                            string loaderPath = System.IO.Path.Combine(PluginLoaderFolder, System.IO.Path.GetFileName(dll));
                            try
                            {
                                if (System.IO.File.Exists(loaderPath)) System.IO.File.Delete(loaderPath);
                            }
                            catch (Exception exc){}

                            if (!System.IO.File.Exists(loaderPath)) System.IO.File.Copy(fullPath, loaderPath);

                            System.Reflection.Assembly asm = System.Reflection.Assembly.LoadFile(loaderPath);
                            if (asm != null)
                            {
                                foreach (Type t in asm.GetTypes())
                                {
                                    foreach (Type i in t.GetInterfaces())
                                    {
                                        if (i.FullName == typeof(IPlugin).FullName)
                                        {
                                            IPlugin plug = (asm.CreateInstance(t.FullName) as IPlugin);
                                            if (plug != null)
                                            {
                                                System.Diagnostics.Trace.Write(string.Format("Plugin Found:{0}, Commands:", plug.GetType().FullName));
                                                plug.RootStore = RootStore;
                                                plug.Messenger = Messenger;
                                                if (plug.Command.Count == 0)
                                                {
                                                    DefaultPlugin = plug;
                                                }
                                                foreach (string cmd in plug.Command)
                                                {
                                                    System.Diagnostics.Trace.Write(cmd);
                                                    System.Diagnostics.Trace.Write(",");
                                                }
                                                System.Diagnostics.Trace.WriteLine("");
                                                PluginList.Add(plug);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        catch (Exception exc)
                        {
                            System.Diagnostics.Trace.WriteLine(exc.ToString());
                            System.Diagnostics.Trace.WriteLine("----------continuing to load plugins-----");
                        }
                    }
                }
            }
        }
    }
}